﻿using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.Windows.Forms;
using System.Threading;
using Microsoft.Xrm.Sdk.Client;

namespace Crm.Utilities.SolutionsDeploymentTool.UI.Helpers
{
    public static class CrmSolutionsHelper
    {
        public static DataCollection<Entity> GetUnmanagedSolutions(IOrganizationService service)
        {
            // Retrieve version number for file name
            QueryExpression querySolutions = new QueryExpression
            {
                EntityName = "solution",
                ColumnSet = new ColumnSet(new string[] { Constants.Solution_FriendlyName, 
                                                         Constants.Solution_UniqueName, 
                                                         Constants.Solution_Version, 
                                                         Constants.Solution_VersionNumber }),
                Criteria = new FilterExpression()
            };

            querySolutions.Criteria.AddCondition(Constants.Solution_IsManaged, ConditionOperator.Equal, false);
            querySolutions.Criteria.AddCondition(Constants.Solution_IsVisible, ConditionOperator.Equal, true);
            querySolutions.Criteria.AddCondition(Constants.Solution_FriendlyName, ConditionOperator.NotEqual, "Default Solution");
            EntityCollection col = service.RetrieveMultiple(querySolutions);

            if (col != null && col.Entities != null)
                return col.Entities;

            return null;
        }

        public static ExecutionMessage ExportCrmSolution(Entity solution, ExportSettings settings, bool exportAsManaged, IOrganizationService service)
        {
            try
            {
                string version = solution.Attributes["version"].ToString().Replace('.', '_');

                // Set Exported solution file name
                string filename;
                if (exportAsManaged) { filename = solution["uniquename"] + "_" + version + "_managed.zip"; }
                else { filename = solution["uniquename"] + "_" + version + ".zip"; }
                
                // Export Solution Request
                ExportSolutionRequest exportRequest = new ExportSolutionRequest
                {
                    Managed = exportAsManaged,
                    SolutionName = solution["uniquename"].ToString(),
                    RequestId = Guid.NewGuid(),
                    ExportAutoNumberingSettings = settings.ExportAutoNumberingSettings,
                    ExportCalendarSettings = settings.ExportCalendarSettings,
                    ExportCustomizationSettings = settings.ExportCustomizationSettings,
                    ExportEmailTrackingSettings = settings.ExportEmailTrackingSettings,
                    ExportGeneralSettings = settings.ExportGeneralSettings,
                    ExportIsvConfig = settings.ExportIsvConfig,
                    ExportMarketingSettings = settings.ExportMarketingSettings,
                    ExportOutlookSynchronizationSettings = settings.ExportOutlookSynchronizationSettings,
                    ExportRelationshipRoles = settings.ExportRelationshipRoles
                };
                ExportSolutionResponse exportResponse = service.Execute(exportRequest) as ExportSolutionResponse;

                // Write to disk
                File.WriteAllBytes(settings.ExportLocation + filename, exportResponse.ExportSolutionFile);
                return new ExecutionMessage(string.Empty, MessageSeverity.Success);
            }
            catch (Exception e)
            {
                return new ExecutionMessage(e.Message, MessageSeverity.Error);
            }
        }

        public static ExecutionMessage ImportCrmSolution(Entity solution, ImportSettings settings, IOrganizationService service)
        {
            string fileLocation = FindMachingSolutionFile(solution, settings.ExportLocation, settings.ImportTypeSetting);
            
            if (String.IsNullOrEmpty(fileLocation))
            {
                return new ExecutionMessage(string.Concat("Matching Solution was not found in folder ", settings.ExportLocation), MessageSeverity.Error);
            }

            return ImportCrmSolution(fileLocation, settings, service);
        }

        public static ExecutionMessage ImportCrmSolution(string fileLocation, ImportSettings settings, IOrganizationService service)
        {
            Guid importJobId = Guid.NewGuid();

            try
            {
                ImportSolutionRequest importSolution = new ImportSolutionRequest
                {
                    OverwriteUnmanagedCustomizations = settings.OverwriteUnmanagedCustomizations,
                    CustomizationFile = File.ReadAllBytes(fileLocation),
                    PublishWorkflows = settings.PublishWorkflows,
                    ConvertToManaged = settings.ConvertToManaged,
                    ImportJobId = importJobId
                };

                try
                {
                    ImportSolutionResponse importResponse = service.Execute(importSolution) as ImportSolutionResponse;
                }
                catch (Exception e)
                {
                    string errorMessage = string.Concat(e.Message, Environment.NewLine, "The Crm Log file has been saved at the following location : ", DownloadImportLogFile(fileLocation, importJobId, service));
                    return new ExecutionMessage(errorMessage, MessageSeverity.Error);
                }
            }
            catch (Exception e)
            {
                string errorMessage = string.Concat(e.Message, Environment.NewLine, "The Crm Log file has been saved at the following location : ", DownloadImportLogFile(fileLocation, importJobId, service));
                return new ExecutionMessage(e.Message, MessageSeverity.Error);
            }
            return new ExecutionMessage(string.Empty, MessageSeverity.Success);
        }

        public static ExecutionMessage  PublishAllCustomizations(IOrganizationService targetService)
        {
            PublishAllXmlResponse response = null;
            PublishAllXmlRequest req = new PublishAllXmlRequest();
            req.RequestId = Guid.NewGuid();

            try
            {
                response = targetService.Execute(req) as PublishAllXmlResponse;
            }
            catch (Exception e)
            {
                return new ExecutionMessage(string.Concat("Publish All customizations failed.", Environment.NewLine, e.Message), MessageSeverity.Error);
            }

            return new ExecutionMessage(string.Empty, MessageSeverity.Success);
        }

        private static string FindMachingSolutionFile(Entity solution, String solutionsFolder, ImportType importType)
        {
            string fileLocation;
            string version = solution.Attributes["version"].ToString().Replace('.', '_');
            if (importType == ImportType.Managed) { fileLocation = solution["uniquename"] + "_" + version + "_managed.zip"; }
            else { fileLocation = solution["uniquename"] + "_" + version + ".zip"; }

            fileLocation = solutionsFolder + fileLocation;
            if (File.Exists(fileLocation))
            {
                return fileLocation;
            }

            return string.Empty;
        }

        private static string DownloadImportLogFile(string path, Guid importJob, IOrganizationService service)
        {
            try
            {
                RetrieveFormattedImportJobResultsRequest importLogRequest = new RetrieveFormattedImportJobResultsRequest()
                {
                    ImportJobId = importJob
                };
                RetrieveFormattedImportJobResultsResponse importLogResponse = (RetrieveFormattedImportJobResultsResponse)service.Execute(importLogRequest);
                String logFilePath = path.Replace(".zip", " ") + DateTime.Now.ToString("yyyy_MM_dd__HH_mm") + ".xml";
                File.WriteAllText(logFilePath, importLogResponse.FormattedResults);
                return logFilePath;
            }
            catch (Exception e)
            {
                return string.Format("Could not download log file ({0})", e.Message);
            }
        }
    }
}
